﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenComposite.EII.Repository;
using OpenComposite.Base;
using WeifenLuo.WinFormsUI.Docking;

namespace OpenComposite.EII.Forms
{
	public partial class FormSearchRepository : DockContent
	{
		public FormSearchRepository(RepositoryService serviceProvider)
		{
			_repSvc = serviceProvider;
			InitializeComponent();
			init();
		}
		private void init()
		{
			_dtHierarchy = null;
			//_dtMain = null;
			_selectedItems = new List<RepositoryItemKey>();

			imageList = Helpers.GetRepositoryItemTypeImageList();
			dgvItems.AutoGenerateColumns = false;

			tscmbDomain.ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
			tscmbDomain.ComboBox.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem);

			fillDomainList();
			tscmbDomain.SelectedIndex = 0;

			tscmbItemType.Items.Add(ItemType.Undefined);
			tscmbItemType.Items.Add(ItemType.Domain);
			tscmbItemType.Items.Add(ItemType.Noun);
			tscmbItemType.Items.Add(ItemType.Capability);
			tscmbItemType.Items.Add(ItemType.Verb);
			tscmbItemType.Items.Add(ItemType.Workflow);
			tscmbItemType.Items.Add(ItemType.BObject);
			tscmbItemType.Items.Add(ItemType.BRule);
			tscmbItemType.Items.Add(ItemType.RuleConstant);
			tscmbItemType.Items.Add(ItemType.LogicalWebMethod);
			tscmbItemType.Items.Add(ItemType.WebService);
			tscmbItemType.Items.Add(ItemType.WebMethod);
			tscmbItemType.Items.Add(ItemType.HumanActivity);

			tscmbItemType.SelectedIndex = 0;

			tscmbItemType.ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
			tscmbItemType.ComboBox.DrawItem += new DrawItemEventHandler(itemTypeComboBox_DrawItem);

			tscmbField.Items.Add(SearchFieldType.All);
			tscmbField.Items.Add(SearchFieldType.Name);
			tscmbField.Items.Add(SearchFieldType.Description);

			tscmbField.SelectedIndex = 0;
		}

		#region Constants
		private const int _textGap = 18;
		private const int _indentWidth = 10;
		#endregion

		#region Public

		public int RepositoryID
		{
			get { return Global.Status.CurrentRepositoryId; }
		}

		#endregion

		#region Internal Members

		#region Properties

		internal Domain SelectedDomain
		{
			get
			{
				DomainItem selected = tscmbDomain.SelectedItem as DomainItem;
				if ( selected != null ) {
					return selected.Item as Domain;
				} else {
					return null;
				}
			}
		}

		internal RepositoryService RepositoryService
		{
			get { return _repSvc; }
		}

		#endregion

		#endregion

		#region Private Members

		#region Methods

		private void searchNow()
		{
			try {
				this.UseWaitCursor = true;
				int domainID = SelectedDomain == null ? 0 : SelectedDomain.ID;
				string searchtext = tstxtTextToFind.Text;
				string name = null;
				string desc = null;
				switch ( (SearchFieldType)tscmbField.SelectedItem ) {
					case SearchFieldType.All:
						name = searchtext;
						desc = name;
						break;
					case SearchFieldType.Name:
						name = searchtext;
						break;
					case SearchFieldType.Description:
						desc = searchtext;
						break;
				}
				DataTable dt = new DataTable();
				ItemType type = ItemType.Undefined;
				if ( tscmbItemType.SelectedItem != null ) {
					type = (ItemType)tscmbItemType.SelectedItem;
				}
				// search items
				if ( name != null ) dt.Merge(Global.Data.SearchRepositoryItems(domainID, type, name, null, false));
				if ( desc != null ) dt.Merge(Global.Data.SearchRepositoryItems(domainID, type, null, desc, false));

				// get column names for dt.DefaultView.ToTable method
				List<string> colNames = new List<string>();
				foreach ( DataColumn col in dt.Columns ) colNames.Add(col.ColumnName);

				// filter internal repository values:
				// 8  - Operation
				// 37 - Diagram
				// 67 - Logical Activity
				string filter = "type <> 67 AND type <> 8 AND type <> 37";
				if ( searchtext.Length <= 2 ) {
					filter += " AND name LIKE '" + searchtext + "%'";
				}
				dt.DefaultView.RowFilter = filter;

				this.dgvItems.ClearSelection();
				// set datasource
				this.dgvItems.DataSource = dt.DefaultView.ToTable(true, colNames.ToArray());
				this.TabText = string.Format("Search Repository ({0} matches found)", dt.DefaultView.Count);
				this.Text = this.TabText;
				// resize columns and sort by type
				this.dgvItems.AutoResizeColumns();
				this.dgvItems.Sort(colType, ListSortDirection.Ascending);
			} finally {
				this.UseWaitCursor = false;
			}
		}
		private void loadRepositoryHierarchy()
		{
			_dtHierarchy = Global.Data.GetRepositoryHierarchy(this.RepositoryID);
		}

		private void fillDomainList()
		{
			if ( _dtHierarchy == null )
				loadRepositoryHierarchy();
			tscmbDomain.BeginUpdate();
			//tscmbFolder.BeginUpdate();
			try {
				tscmbDomain.Items.Clear();
				// add "All Domains" item
				tscmbDomain.Items.Add(new DomainItem(null, 0, "All Domains", null, null));
				// select top domains
				DataRow[] rows;
				rows = _dtHierarchy.Select("parent_reptype_id IS NULL AND parent_id IS NULL AND " +
							 string.Format("child_reptype_id = {0}", (int)ItemType.Domain));

				foreach ( DataRow row in rows ) {
					// add domain to combobox
					addDomainToList(row, 0);
				}

				// auto-width combobox dropdown
				using ( Graphics g = tscmbDomain.ComboBox.CreateGraphics() ) {
					foreach ( DomainItem dom in tscmbDomain.Items ) {
						SizeF sz = g.MeasureString(dom.Text, tscmbDomain.Font);
						int itemwidth = (int)Math.Ceiling(sz.Width) + dom.Indent + _textGap + 18/*scrollbar*/;
						if ( itemwidth > tscmbDomain.DropDownWidth )
							tscmbDomain.DropDownWidth = itemwidth;
					}
				}
			} finally {
				tscmbDomain.EndUpdate();
				//tscmbFolder.EndUpdate();
			}
		}

		private void addDomainToList(DataRow currentRow, int indent)
		{
			ItemType type = (ItemType)currentRow["child_reptype_id"];
			int id = (int)currentRow["child_id"];

			//if ( !this.AllowChangeDomain && id != this.DomainID )
			//    return;

			IRepositoryItem item = this.RepositoryService.GetItem(type, id, false);

			string text = currentRow["child_display"].ToString();
			string imgkey = currentRow.IsNull("child_image_key") ? item.ImageKey : currentRow["child_image_key"].ToString();

			// create domain item if current item is a domain
			DomainItem currentDomainItem = new DomainItem(imageList.Images[imgkey], indent, text, item, currentRow);
			tscmbDomain.Items.Add(currentDomainItem);

			// get child domains
			DataRow[] rows = _dtHierarchy.Select(string.Format(
					"parent_reptype_id = {0} AND parent_id = {1} AND child_reptype_id = {2}",
					(int)type, id, (int)ItemType.Domain));

			foreach ( DataRow row in rows ) {
				tscmbDomain.Items.Add(item);
			}
		}

		#endregion

		#region Fields

		//private DataTable _dtMain;
		private DataTable _dtHierarchy = null;
		private ImageList imageList;
		private RepositoryService _repSvc;
		private List<RepositoryItemKey> _selectedItems;

		#endregion

		#region Event Handlers

		private void tsbtnSearch_Click(object sender, EventArgs e)
		{
			searchNow();
		}

		private void tstxtTextToFind_KeyUp(object sender, KeyEventArgs e)
		{
			if ( e.KeyCode == Keys.Enter ) {
				searchNow();
			}
		}

		private void dgvItems_CellClick(object sender, DataGridViewCellEventArgs e)
		{
			if ( e.ColumnIndex == colType.Index && e.RowIndex > -1 ) {
				DataGridViewRow row = dgvItems.Rows[e.RowIndex];
				DataGridViewTextBoxCell cell = row.Cells[colType.Index] as DataGridViewTextBoxCell;
				if ( cell != null ) {
					DataRowView dr = row.DataBoundItem as DataRowView;
					RepositoryItemKey key = new RepositoryItemKey((ItemType)dr["type"],
																  (int)dr["id"]);
					if ( key.Type != (ItemType)tscmbItemType.SelectedItem )
						return;
					_selectedItems.Clear();
					_selectedItems.Add(key);
				}
			}
		}
		private void dgvItems_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
		{
			//if ( tscmbDomain.ComboBox.DrawItem == null ) tscmbDomain.ComboBox.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem);
			if ( e.RowIndex >= 0 && dgvItems.Columns[e.ColumnIndex].Name == colType.Name && e.Value is int &&
				 Enum.IsDefined(typeof(ItemType), (int)e.Value) ) {
				// custom paint at itemtype column
				ItemType type = (ItemType)e.Value;
				bool selected = ( ( e.State & DataGridViewElementStates.Selected ) > 0 );
				e.PaintBackground(e.CellBounds, selected);
				string key = "";
				if ( selected )
					key = _repSvc.GetSelectedImageKey(type);
				else
					key = _repSvc.GetImageKey(type);
				if ( key != "" ) {
					Rectangle r = e.CellBounds;
					r.Inflate(-1, -1);
					Image img = imageList.Images[key];
					if ( img != null )
						e.Graphics.DrawImageUnscaled(img, r.X, r.Y, 18, 18);
				}
				e.Handled = true;
			} else if ( e.RowIndex > -1 && e.ColumnIndex == colType.Index ) {
				DataGridViewRow row = dgvItems.Rows[e.RowIndex];
				if ( row != null ) {
					DataRowView dr = row.DataBoundItem as DataRowView;
					RepositoryItemKey key = new RepositoryItemKey((ItemType)dr["type"],
																  (int)dr["id"]);
					if ( key.Type != (ItemType)tscmbItemType.SelectedItem ) {
						bool selected = ( ( e.State & DataGridViewElementStates.Selected ) > 0 );
						e.PaintBackground(e.CellBounds, selected);
						e.Handled = true;
					}
				}
			} else if ( e.RowIndex >= 0 && dgvItems.Columns[e.ColumnIndex].Name == colType.Name ) {
			} else {
				e.Handled = false;
			}
		}
		private void dgvItems_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
		{
			if ( e.RowIndex > -1 ) {
				showSelectedItemDetails();
			}
		}

		private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
		{
			e.DrawBackground();
			if ( ( e.State & DrawItemState.Focus ) == DrawItemState.Focus )
				e.DrawFocusRectangle();

			if ( e.Index < 0 || e.Index >= tscmbDomain.Items.Count ) {
				using ( StringFormat sf = new StringFormat() ) {
					sf.Trimming = StringTrimming.None;
					sf.Alignment = StringAlignment.Center;
					sf.LineAlignment = StringAlignment.Center;
					e.Graphics.DrawString("- No Domain Available -", e.Font, SystemBrushes.GrayText, e.Bounds, sf);
				}
			} else {
				FolderItem item = tscmbDomain.Items[e.Index] as FolderItem;
				if ( item != null ) {
					int indent = _indentWidth * item.Indent + 2;
					int textGap = 0;

					// draw image
					if ( item.Image != null ) {
						textGap = _textGap;
						Rectangle rectImg = new Rectangle(e.Bounds.X + indent, e.Bounds.Y,
														  _textGap, e.Bounds.Height);
						e.Graphics.DrawImageUnscaled(item.Image, rectImg);
					}
					// draw text
					RectangleF rectText = new RectangleF(e.Bounds.Left + textGap + indent, e.Bounds.Y,
														 e.Bounds.Width - textGap - indent, e.Bounds.Height);
					using ( StringFormat sf = new StringFormat() )
					using ( Brush b = new SolidBrush(e.ForeColor) ) {
						sf.Trimming = StringTrimming.EllipsisCharacter;
						if ( item.Item == null )	// All <ITEMTYPENAME>
							sf.Alignment = StringAlignment.Center;
						else
							sf.Alignment = StringAlignment.Near;
						sf.LineAlignment = StringAlignment.Center;
						e.Graphics.DrawString(item.Text, e.Font, b, rectText, sf);
					}

				} else {
					using ( StringFormat sf = new StringFormat() )
					using ( Brush b = new SolidBrush(e.ForeColor) ) {
						sf.Trimming = StringTrimming.EllipsisCharacter;
						sf.Alignment = StringAlignment.Near;
						sf.LineAlignment = StringAlignment.Center;
						e.Graphics.DrawString(tscmbDomain.Items[e.Index].ToString(), e.Font, b, e.Bounds, sf);
					}
				}
			}
		}

		private void itemTypeComboBox_DrawItem(object sender, DrawItemEventArgs e)
		{
			e.DrawBackground();
			if ( ( e.State & DrawItemState.Focus ) == DrawItemState.Focus )
				e.DrawFocusRectangle();

			if ( e.Index < 0 || e.Index >= tscmbItemType.Items.Count ) {
				using ( StringFormat sf = new StringFormat() ) {
					sf.Trimming = StringTrimming.None;
					sf.Alignment = StringAlignment.Center;
					sf.LineAlignment = StringAlignment.Center;
					e.Graphics.DrawString("- No Type Selected -", e.Font, SystemBrushes.GrayText, e.Bounds, sf);
				}
			} else {
				ItemType item = (ItemType)tscmbItemType.Items[e.Index];
				int indent = _indentWidth * 2;
				int textGap = 0;

				// draw image
				Image img = ItemTypes.GetImage(item);
				string text = ItemTypes.GetDisplay(item);
				if ( item == ItemType.Undefined ) text = "All Types";
				if ( img != null ) {
					Rectangle rectImg = new Rectangle(e.Bounds.X, e.Bounds.Y,
														  16, 16);
					e.Graphics.DrawImage(img, rectImg);
				}
				// draw text
				RectangleF rectText = new RectangleF(e.Bounds.Left + textGap + indent, e.Bounds.Y,
													 e.Bounds.Width - textGap - indent, e.Bounds.Height);
				using ( StringFormat sf = new StringFormat() )
				using ( Brush b = new SolidBrush(e.ForeColor) ) {
					sf.Trimming = StringTrimming.EllipsisCharacter;
					sf.Alignment = StringAlignment.Near;
					sf.LineAlignment = StringAlignment.Center;
					e.Graphics.DrawString(text, e.Font, b, rectText, sf);
				}
			}
		}

		#endregion

		#endregion

		private void editToolStripMenuItem_Click(object sender, EventArgs e)
		{
			showSelectedItemDiagram();
		}

		private void viewDetailsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			showSelectedItemDetails();
		}

		private void dgvItems_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
		{
			if ( e.Clicks == 1 && e.Button == MouseButtons.Right ) {
			}
		}

		private void dgvItems_KeyUp(object sender, KeyEventArgs e)
		{
			if ( e.Alt && e.Control && e.KeyCode == Keys.I ) {
				DataRowView drv = dgvItems.SelectedRows[0].DataBoundItem as DataRowView;
				RepositoryItemBase item = Global.Data.RepositoryService.GetItem((ItemType)drv["type"], (int)drv["id"], false) as RepositoryItemBase;
				Helpers.OpenDebugViewer(item, this);
			}
		}

		private void showSelectedItemDiagram()
		{
			if ( dgvItems.SelectedRows.Count < 1 ) return;
			DataRowView drv = dgvItems.SelectedRows[0].DataBoundItem as DataRowView;
			if ( ItemTypes.HasDiagram((ItemType)drv["type"]) ) {
				RepositoryItemBase item = Global.Data.RepositoryService.GetItem((ItemType)drv["type"], (int)drv["id"], false) as RepositoryItemBase;
				Helpers.OpenDiagram(item, _repSvc);
			}
		}

		private void showSelectedItemDetails()
		{
			if ( dgvItems.SelectedRows.Count < 1 ) return;
			DataRowView row = dgvItems.SelectedRows[0].DataBoundItem as DataRowView;
			if ( row != null ) {
				ItemType type = (ItemType)row["type"];
				int id = (int)row["id"];
				Helpers.ShowDetails(id, type, _repSvc);
			}
		}

		private void dgvItems_Paint(object sender, PaintEventArgs e)
		{
			if ( dgvItems.Rows.Count == 0 ) {
				string msg = "No matches found!";
				SizeF size = e.Graphics.MeasureString(msg, dgvItems.Font, dgvItems.ClientSize.Width);
				float x = dgvItems.Width / 2 - size.Width / 2;
				float y = ( dgvItems.Height / 2 - size.Height / 2 ) + dgvItems.ColumnHeadersHeight / 2;
				e.Graphics.DrawString(msg, dgvItems.Font, Brushes.DarkGray, x, y);
			}
		}

		private void dgvItems_Resize(object sender, EventArgs e)
		{
			this.Refresh();
		}

		private void dgvItems_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
		{
			if ( e.RowIndex >= 0 ) {
				dgvItems[e.ColumnIndex, e.RowIndex].Selected = true;
				DataRowView drv = dgvItems.Rows[e.RowIndex].DataBoundItem as DataRowView;
				if ( drv != null ) {
					editToolStripMenuItem.Visible = ItemTypes.HasDiagram((ItemType)drv["type"]);
					e.ContextMenuStrip = contextMenuStrip1;
				}
			}
		}

		private void dgvItems_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
		{
			try {
				if ( e.ColumnIndex == colFolder.DisplayIndex ) {
					DataRowView row = dgvItems.Rows[e.RowIndex].DataBoundItem as DataRowView;
					int id = (int)row.Row["id"];
					ItemType type = (ItemType)row.Row["type"];

					//IRepositoryItem item = Global.Data.RepositoryService.GetItem(
					DataRow[] rows = _dtHierarchy.Select(
						string.Format("child_id={0} AND child_reptype_id={1}", id, (int)type));
					if ( rows.Length > 0 ) {
						//DataRow displayRow = null;
						if ( rows[0]["parent_display"] is string ) {
							e.Value = (string)rows[0]["parent_display"];
						} else {
							e.Value = "";
						}
						//displayRow = rows[0];
						if ( rows.Length > 1 ) {
							foreach ( DataRow dRow in rows ) {
								if ( (int)dRow["parent_reptype_id"] == (int)ItemType.GenericFolder ) {
									e.Value = dRow["parent_display"] as string + ", ...";
									//displayRow = dRow;
								}
							}
							StringBuilder sb = new StringBuilder();
							//sb.Append("Element is also child of:");
							foreach ( DataRow dRow in rows ) {
								//if ( dRow == displayRow ) continue;
								if ( dRow != rows[0] ) {
									sb.AppendLine();
								}
								sb.Append(dRow["parent_display"].ToString());
								//if ( dRow != rows[rows.Length - 1] ) {
								//    sb.AppendLine();
								//}
							}
							dgvItems[e.ColumnIndex, e.RowIndex].ToolTipText = sb.ToString();
						}
					}
					e.FormattingApplied = true;
				}
			} catch {

			}
		}

		private void dgvItems_DataError(object sender, DataGridViewDataErrorEventArgs e)
		{
		}
	}

	public enum SearchFieldType
	{
		All,
		Name,
		Description
	}
}
